package org.sagitta.httprpc;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sagitta.httprpc.annotation.Default;
import org.sagitta.httprpc.message.Request;
import org.sagitta.httprpc.message.Response;
import org.sagitta.httprpc.utils.CommonUtil;

class MappedController {
	private static final Log log = LogFactory.getLog(MappedController.class);
	private ControllerBase controller;
	private Map<String, WebAction> actions;
	private String defaultAction;
	private boolean initialized = false;

	/**
	 * Initialize the controller by the controller name
	 * 
	 * @param packageName
	 *            the controller package name
	 * @param controllerName
	 *            the controller name
	 */
	public void initializeController(String packageName, String controllerName) {
		try {
			String className = packageName + "." + controllerName + "Controller";
			log.info("Looking up the web actions in controller: " + className + "...");
			Class<?> clazz = Class.forName(className);
			Object controllerInstance = clazz.newInstance();
			if (controllerInstance instanceof ControllerBase) {
				controller = (ControllerBase) controllerInstance;
				lookupActionMethods();
				initialized = true;
			} else {
				log.warn(className + " is not a validate controller, it has to be inherited from ControllerBase");
			}
		} catch (ClassNotFoundException e) {
			log.warn("Class not found with controller " + controllerName);
		} catch (InstantiationException e) {
			log.warn("Can not create instance on Class:" + controllerName);
		} catch (IllegalAccessException e) {
			log.warn("Can not create instance on Class:" + controllerName);
		}
	}

	@SuppressWarnings("unchecked")
	private void lookupActionMethods() {
		actions = new HashMap<String, WebAction>();
		Method[] methods = controller.getClass().getMethods();
		for (Method method : methods) {
			if (Response.class.isAssignableFrom(method.getReturnType())) {
				Class[] paramsClazzs = method.getParameterTypes();
				if (paramsClazzs.length == 1 && Request.class.isAssignableFrom(paramsClazzs[0])) {
					log.info("Found a web action [" + method.getName() + "] in: " + controller.getClass().getSimpleName());
					actions.put(method.getName(), new WebAction(this.controller, method, paramsClazzs[0]));
					if (defaultAction == null && method.getAnnotation(Default.class) != null) {
						defaultAction = method.getName();
						log.info(controller.getClass().getSimpleName() + " default action is [" + defaultAction + "]");
					}
				}
			}
		}
	}

	public WebAction getAction(String actionName) {
		if (!this.initialized) {
			log.error("The controller hasn't been initialized.");
			return null;
		}
		if (CommonUtil.isNullString(actionName)) {
			actionName = defaultAction;
		}
		return actions.get(actionName);
	}

}
